#pragma once
#ifndef OBR_ANIMATION_H
#define OBR_ANIMATION_H

#include "ASNode.h"
#include "Configurable.h"
#include "Instance.h"
#include "Transform.h"
#include "common.h"
#include "helpers/Helpers.h"

namespace OBR
{
class Scene;

class Animation : public Instance
{
public:
    float tmin = 0.0f, tmax = 1.0f;
    uint flags = OPTIX_MOTION_FLAG_NONE;
    std::shared_ptr<ASNode> child = nullptr;

protected:
    CudaBuffer d_transform_buffer;
    int child_id = -1;

public:
    Animation();
    virtual ~Animation();

    /**
     * @brief set local to world transform to given parent value and pass down to none GAS children
     *
     * @param l2w
     */
    void updateLocalToWorld(Matrix4x4f l2w) override;

    /**
     * @brief link children using child data
     *
     * @param materials
     * @param mediums
     * @param meshes
     * @param instances
     */
    void linkChild(VirtualProgramManager materials, VirtualProgramManager mediums,
                   VirtualProgramManager meshes, VirtualProgramManager lights,
                   std::vector<std::shared_ptr<Instance>> instances) override;

private:
    virtual void setupMotionTransformBlock(void **dst, uint &num_keys, uint &size) = 0;
};

class MatrixAnimation : public Animation, public Configurable<MatrixAnimation>
{
public:
    std::vector<std::shared_ptr<Transform>> transforms = {};

public:
    MatrixAnimation();
    ~MatrixAnimation();

    void buildAccelStructure(OptixDeviceContext &ctx, CUstream &stream) override;

    void updateAccelStructure() override;

    void postBuild(Scene &sc) override;

protected:
    void _buildFromConfig(const Json::Value &config) override;

private:
    void setupMotionTransformBlock(void **dst, uint &num_keys, uint &size) override;
};

class SRTAnimation : public Animation, public Configurable<SRTAnimation>
{
public:
    std::vector<std::shared_ptr<SRTTransform>> transforms = {};

public:
    SRTAnimation();
    ~SRTAnimation();

    void buildAccelStructure(OptixDeviceContext &ctx, CUstream &stream) override;

    void updateAccelStructure() override;

    void postBuild(Scene &sc) override;

protected:
    void _buildFromConfig(const Json::Value &config) override;

private:
    void setupMotionTransformBlock(void **dst, uint &num_keys, uint &size) override;
};
} // namespace OBR

#endif
